import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:path/path.dart' as p;
import 'package:shared_preferences/shared_preferences.dart';

import 'internal/path_resolver.dart'; // 根据工程实际路径调整
import 'logic/node_file_ops.dart' as fops;
import 'logic/node_menu.dart' as node_menu;
import 'node_tile.dart';
import 'utils/default_file_icon.dart';

/// # NodeTileState
///
/// 负责节点（文件 / 文件夹）在资源管理器中的交互与 UI：
/// - 悬停效果、选中高亮、展开/收起动画；
/// - 单击 / 双击 / 右键菜单的行为；
/// - 子节点递归渲染。
class NodeTileState extends State<NodeTile> {
  // ───── 状态字段 ─────
  /// 鼠标是否悬停
  bool _hover = false;

  /// “乐观选中”标志，避免点击后到父组件真正 setState
  /// 之间的闪烁。
  bool _optimisticSelect = false;

  // ───── 生命周期 ─────
  @override
  void didUpdateWidget(covariant NodeTile oldWidget) {
    super.didUpdateWidget(oldWidget);

    // 外层 selected 更新时，把乐观选中清掉
    if (_optimisticSelect && (widget.selected != oldWidget.selected)) {
      _optimisticSelect = false;
    }
    if (_optimisticSelect && widget.selected) {
      _optimisticSelect = false;
    }
  }

  // ────────────────────────────── 右键菜单 ──────────────────────────────

  /// 弹出右键菜单，并根据返回值执行对应操作
  Future<void> _showContextMenu(TapDownDetails details) async {
    final result = await node_menu.showNodeContextMenu(
      context,
      details,
      isFolder: widget.node.isFolder,
      // 仅当节点为 **project.cloud 文件** 时启用 Generate
      enableGenerate:
          !widget.node.isFolder && widget.node.name == 'project.cloud',
    );

    switch (result) {
      case 'delete':
        widget.onDelete(widget.path, widget.node);
        break;
      case 'new_file':
        await fops.handleCreate(
          context: context,
          widget: widget,
          isFolder: false,
        );
        break;
      case 'new_folder':
        await fops.handleCreate(
          context: context,
          widget: widget,
          isFolder: true,
        );
        break;
      case 'rename':
        await fops.handleRename(context: context, widget: widget);
        break;
      case 'generate':
        await _handleGenerate(); // ← 新增
        break;
      default:
        break;
    }
  }

  // ────────────────────────────── Generate 实现 ──────────────────────────────

  /// 处理 Generate：执行 `exePath generate`
  ///
  /// 步骤：
  /// 1. 解析出 project.cloud 的真实磁盘路径；
  /// 2. 获取 SDK 目录中的可执行文件 (Snow.exe / snow)；
  /// 3. 使用 `Process.start` 启动子进程并监听退出码；
  /// 4. 结果通过 SnackBar 告知用户。
  Future<void> _handleGenerate() async {
    // 1. 解析出真实路径
    String realPath = widget.node.fullPath ?? '';
    if (realPath.isEmpty) {
      // 若 Node 没带路径，使用外部解析器
      final resolver = PathResolver(external: widget.realPathResolver);
      realPath = resolver.resolve(widget.path, widget.node);
    }

    if (realPath.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Unable to resolve project.cloud path')),
      );
      return;
    }

    final projectRoot = p.dirname(realPath);

    // 2. 准备可执行文件路径
    final exePath = await _prepareSnowExecutable();

    // 3. 启动进程
    final process = await Process.start(
      exePath,
      const ['generate'],
      workingDirectory: projectRoot,
      runInShell: false,
    );

    // 将 stdout / stderr 打印到调试控制台
    process.stdout.transform(const Utf8Decoder()).listen(debugPrint);
    process.stderr.transform(const Utf8Decoder()).listen(debugPrint);

    // 4. 根据退出码提示
    final code = await process.exitCode;
    if (code == 0) {}
  }

  /// 获取 Snow 可执行文件路径
  ///
  /// - SDK 根目录保存在 `SharedPreferences` 的 `sdk_current_path`。
  /// - Windows：`<SDK>/bin/Snow.exe`
  /// - macOS / Linux：`<SDK>/bin/snow`
  /// - 若未配置或文件不存在，则抛异常。
  Future<String> _prepareSnowExecutable() async {
    const sdkKey = 'sdk_current_path';
    final prefs = await SharedPreferences.getInstance();
    final sdkPath = prefs.getString(sdkKey) ?? '';

    if (sdkPath.isEmpty) {
      throw Exception('No SDK selected in Settings');
    }

    final exeName = Platform.isWindows ? 'Snow.exe' : 'snow';
    final exePath = p.join(sdkPath, 'bin', exeName);

    if (!await File(exePath).exists()) {
      throw Exception('Snow executable not found at $exePath');
    }
    return exePath;
  }

  // ────────────────────────────── 业务无关：节点点击 / 渲染 ──────────────────────────────

  /// 立即“乐观选中”并排队真正回调
  void _selectNowOptimistically() {
    if (!_optimisticSelect && !widget.selected) {
      setState(() => _optimisticSelect = true);
    }
    Future.microtask(() => widget.onSelect(widget.path, widget.node));
  }

  /// 双击：文件夹 → 展开；文件 → 打开
  void _handleDoubleTap(bool isFolder) {
    _selectNowOptimistically();
    if (isFolder) {
      widget.onToggle(widget.node, widget.path);
    } else {
      Future.microtask(() => widget.onOpen(widget.path, widget.node));
    }
  }

  // ────────────────────────────── 构建 UI ──────────────────────────────

  @override
  Widget build(BuildContext context) {
    final t = widget.theme;
    final isFolder = widget.node.isFolder;
    final isExpanded = widget.expanded;

    // 当前是否显示为选中（含乐观选中）
    final isVisuallySelected = widget.selected || _optimisticSelect;

    // 背景色：选中 / 悬停 / 默认
    final bgColor = isVisuallySelected
        ? t.selectionColor
        : (_hover ? t.hoverColor : Colors.transparent);

    // 节点文字样式
    final textStyle = TextStyle(
      fontSize: 13,
      color: t.textColor,
      fontWeight: isVisuallySelected ? FontWeight.w500 : FontWeight.normal,
    );

    // 获取子节点（通常配合缓存）
    final children = widget.getChildren();

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // ─── 节点（单行） ───
        MouseRegion(
          onEnter: (_) => setState(() => _hover = true),
          onExit: (_) => setState(() => _hover = false),
          child: GestureDetector(
            behavior: HitTestBehavior.opaque,
            onTapDown: (_) => _selectNowOptimistically(),
            onDoubleTap: () => _handleDoubleTap(isFolder),
            onSecondaryTapDown: _showContextMenu,
            // ← 右键菜单
            onTapCancel: () {
              // 若取消点击，回退乐观选中
              if (_optimisticSelect && !widget.selected) {
                setState(() => _optimisticSelect = false);
              }
            },
            child: RepaintBoundary(
              child: Container(
                height: widget.rowHeight,
                color: bgColor,
                padding: EdgeInsets.only(
                  left: 8 + widget.depth * 16.0, // 缩进
                  right: 8,
                ),
                child: LayoutBuilder(
                  builder: (context, constraints) {
                    // 宽度过窄时直接占位
                    const double kLeadingMinWidth = 42.0;
                    final bool tooNarrow =
                        constraints.maxWidth < (kLeadingMinWidth + 4);
                    if (tooNarrow) return const SizedBox.expand();

                    return Row(
                      children: [
                        // 展开 / 收起箭头（仅文件夹）
                        SizedBox(
                          width: 18,
                          child: isFolder
                              ? GestureDetector(
                                  behavior: HitTestBehavior.opaque,
                                  onTap: () {
                                    _selectNowOptimistically();
                                    widget.onToggle(widget.node, widget.path);
                                  },
                                  child: AnimatedRotation(
                                    turns: isExpanded ? 0.25 : 0.0,
                                    duration: widget.animDuration,
                                    child: Icon(
                                      Icons.chevron_right,
                                      size: 16,
                                      color: Colors.grey[700],
                                    ),
                                  ),
                                )
                              : const SizedBox.shrink(),
                        ),
                        // 图标
                        Icon(
                          isFolder
                              ? (isExpanded ? Icons.folder_open : Icons.folder)
                              : defaultFileIcon(widget.node.name),
                          size: 18,
                          color: isFolder
                              ? t.folderColor
                              : widget.fileColorResolver!(widget.node.name),
                        ),
                        const SizedBox(width: 6),
                        // 文件 / 文件夹名
                        Expanded(
                          child: Align(
                            alignment: Alignment.centerLeft,
                            child: Text(
                              widget.node.name,
                              style: textStyle,
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                              softWrap: false,
                            ),
                          ),
                        ),
                      ],
                    );
                  },
                ),
              ),
            ),
          ),
        ),

        // ─── 子节点区域（展开时渲染） ───
        AnimatedSwitcher(
          duration: widget.animDuration,
          switchInCurve: Curves.easeOutCubic,
          switchOutCurve: Curves.easeInCubic,
          child: (isFolder && (widget.isLoading || isExpanded))
              ? Column(
                  key: ValueKey(
                    '${widget.path}-${widget.isLoading}-$isExpanded',
                  ),
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    // 加载中
                    if (widget.isLoading)
                      Padding(
                        padding: EdgeInsets.only(
                          left: 8 + (widget.depth + 1) * 16.0,
                          top: 4,
                          bottom: 6,
                          right: 8,
                        ),
                        child: Row(
                          mainAxisSize: MainAxisSize.min,
                          children: const [
                            SizedBox(
                              width: 14,
                              height: 14,
                              child: CircularProgressIndicator(strokeWidth: 2),
                            ),
                            SizedBox(width: 8),
                          ],
                        ),
                      ),
                    if (widget.isLoading)
                      Padding(
                        padding: EdgeInsets.only(
                          left: 8 + (widget.depth + 1) * 16.0,
                          bottom: 6,
                          right: 8,
                        ),
                        child: Text(
                          'Loading...',
                          style: TextStyle(
                            color: widget.theme.secondaryTextColor,
                          ),
                        ),
                      ),

                    // 展开状态：递归渲染子节点
                    if (!widget.isLoading && isExpanded)
                      ...children.map((child) {
                        final childPath = '${widget.path}/${child.name}';
                        final childExpanded = widget.isExpanded(childPath);
                        final childSelected = widget.selectedPath == childPath;

                        return NodeTile(
                          node: child,
                          depth: widget.depth + 1,
                          path: childPath,
                          expanded: childExpanded,
                          selected: childSelected,
                          isLoading: false,
                          getChildren: () =>
                              widget.resolveChildren(child, childPath),
                          resolveChildren: widget.resolveChildren,
                          onToggle: widget.onToggle,
                          onSelect: widget.onSelect,
                          onOpen: widget.onOpen,
                          onDelete: widget.onDelete,
                          onRename: widget.onRename,
                          isExpanded: widget.isExpanded,
                          selectedPath: widget.selectedPath,
                          theme: widget.theme,
                          fileColorResolver: widget.fileColorResolver,
                          rowHeight: widget.rowHeight,
                          animDuration: widget.animDuration,
                          realPathResolver: widget.realPathResolver,
                        );
                      }),
                  ],
                )
              : const SizedBox.shrink(),
        ),
      ],
    );
  }
}
